uniform sampler2D bgTexture;

struct View3D {
	float ssaa;
	mediump int w;
	mediump int h;
	mediump int skylineFromTopPx;
	mediump int fadeOffsetSkylinePx;
	mediump int fadeOffsetHorizonPx;
};
uniform View3D view3d;

const float FadeEndZFragCoordY_None = -1000000.0;

vec3 fadeOutEdge(vec3 color, float fadeEndZFragCoordY, int fadeZOffsetPx) {
	float S = view3d.ssaa;
	float skylineY = float(view3d.h - view3d.skylineFromTopPx) * S;
	if (gl_FragCoord.y > skylineY) {// gl_FragCoord's unit is float not int; gl_FragCoord's (0,0) is bottom-left
		// The statement will immediately terminate the processing of the current fragment, so there is no need to explicitly use a return.
		// Discard will discard the current fragment, preventing it from being further processed or written to the frame buffer.
		discard;
	}
	float viewW = float(view3d.w) * S;
	float viewH = float(view3d.h) * S;
	float fadeHD = float(view3d.fadeOffsetHorizonPx) * S;
	float fadeSkylineD = float(view3d.fadeOffsetSkylinePx) * S;
	float fadeEndZFragY = fadeEndZFragCoordY * S;
	float fadeZOffsetD = float(fadeZOffsetPx) * S;
	float deltaPrecision = 2.0;// line&roadEdge has a 3d-height and float loss precision, may lead to edge is not included for fading!
	bool fadeVerticalByEndZ = fadeEndZFragCoordY != FadeEndZFragCoordY_None && gl_FragCoord.y <= fadeEndZFragY + deltaPrecision && abs(gl_FragCoord.y - fadeEndZFragY - deltaPrecision) <= fadeZOffsetD;
	bool fadeVerticalDef = fadeEndZFragCoordY == FadeEndZFragCoordY_None && gl_FragCoord.y > skylineY - fadeSkylineD;
	if (gl_FragCoord.x < fadeHD || gl_FragCoord.x > viewW - fadeHD || fadeVerticalByEndZ || fadeVerticalDef) {
		vec2 texCoord = vec2(gl_FragCoord.x / viewW, gl_FragCoord.y / viewH);
		vec3 bgColor = texture(bgTexture, texCoord).rgb;
		float f = 0.0;
		if (gl_FragCoord.x < fadeHD)
			f = abs(gl_FragCoord.x - fadeHD) / fadeHD;
		else if (gl_FragCoord.x > viewW - fadeHD)
			f = abs(gl_FragCoord.x - viewW + fadeHD) / fadeHD;
		if (f > 0.0)
			color = mix(color, bgColor, f);

		if (fadeVerticalByEndZ) {
			f = 1.0 - abs(gl_FragCoord.y - fadeEndZFragY) / fadeZOffsetD;
			f = smoothstep(0.0, 1.0, f);
		} else if (fadeVerticalDef)
			f = abs(gl_FragCoord.y - skylineY + fadeSkylineD) / fadeSkylineD;
		color = mix(color, bgColor, f);
	}
	return color;
}

vec3 fadeOutView3dEdge(vec3 color) {
	return fadeOutEdge(color, FadeEndZFragCoordY_None, 0);
}